package mkv.MyGUI;
import processing.core.*;

/**
 * <p>MyGUIStyle is a simple collection of colours and a font(s) that is used to
 * give a constant look and feel to all elements drawn through processing.</p>
 * <p>Version: 0.01<br/>
 * Created by John Beech<br/>
 * Website: http://mkv25.net/</p>
 * <p>MyGUIStyle objects contain many variables used by almost all MyGUI elements.
 * Each of the variables are public and can be accessed by . syntax, for example:<br>
 * MyGUIStyle style1 = new MyGUIStyle(this);<br>
 * PApplet.color back = style1.background;</p>
 * <p>In the list below, variable names are inside the (brackets).
 * <ul>
 * <li>Specify font, font size</li>
 * <li>Set colours for:
 *   <ul>
 *   <li>Background (background)</li>
 *   <li>Button Face (buttonFace)</li>
 *   <li>Button Highlight (buttonHighlight)</li>
 *   <li>Button Shadow (buttonShadow)</li>
 *   <li>Button Text (buttonText)</li>
 *   <li>General Icon (icon)</li>
 *   <li>General Face (face)</li>
 *   <li>General Highlight (highlight)</li>
 *   <li>General Shadow (shadow)</li>
 *   <li>General Disabled (disabled)</li>
 *   <li>Highlighted Text (highlightText)</li>
 *   <li>Scroll Bar Background (scrollBar)</li>
 *   </ul>
 * </li>
 * </ul>
 * </p>
 *
 */

public class MyGUIStyle {
  // Variables (public as they will need to be referenced easily)
  private PApplet _root;
  public PFont font;
  public int fontSize = 12, strokeWeight = 1, padding = 1;
  private float transparency = 255;
  public int background, buttonFace, buttonHighlight, buttonShadow, buttonText, icon, highlight, face, shadow, disabled, highlightText, scrollBar;
  
  // Constructors
  // Default, sets up default colours
  /**
   * The most basic constructor for MyGUIStyle objects. Sets the default colours
   * and loads the font ArialNarrow-48.vlw. MyGUIStyle like all MyGUI objects need a
   * reference to a processing PApplet object so that they can call load and draw methods.
   * 
   * @param root  root points back to the processing PApplet used to call the MyGUI library.
   */
  public MyGUIStyle(PApplet root) {
    this._root = root;
    this.font = _root.loadFont("FedraSans-Book-24.vlw");
    setDefaultColors();
  }

  /**
   * This constructor lets you specify a shade to tint all the colours to.
   * Sets the default colours, tints them based off the provided color 
   * and loads the font ArialNarrow-48.vlw.
   * 
   * @param root  points back to the processing PApplet used to call the MyGUI library.
   * @param tint  specifies the color value used to shade the default colours.
   * 
   * @see   #tintColor(int c)
   */
  public MyGUIStyle(PApplet root, int tint) {
    this._root = root;
    this.font = _root.loadFont("ArialNarrow-48.vlw");
    setDefaultColors();
    tintColor(tint);
  }
      
  // Full advanced constructor, font, fontSize and all colours
  /**
   * This constructor takes inputs for a custom (preloaded) font and all of the colours as PApplet.color() values.
   * The constructor completely ignores the default colours and lets you set custom values. 
   * 
   * @param root        points back to the processing PApplet used to call the MyGUI library.
   * @param font        preloaded PFont reference to define the font used for text.
   * @param fontSize    the size of font to use for elements.
   * @param background  the color of background elements.
   * @param buttonFace  the color for button faces.
   * @param buttonHighlight  the color for highlights on buttons.
   * @param buttonShadow  the color for shadows/alternate colours on buttons. 
   * @param buttonText  the color for text on buttons.
   * @param icon				the color for class specific icons.
   * @param face        a generic face color.
   * @param highlight   a generic highlight color.
   * @param shadow      a generic shadow color.
   * @param disabled    a color for disabled elements.
   * @param highlightText  the color for highlighted text.
   * @param scrollBar   the color for the backing of a scroll bar
   * 
   */
  public MyGUIStyle(PApplet root, PFont font, int fontSize, int background, int buttonFace, int buttonHighlight, int buttonShadow,
    int buttonText, int icon, int face, int highlight, int shadow, int disabled, int highlightText, int scrollBar)
  {
    this._root = root;  
    this.font = font;
    this.fontSize = fontSize;
    this.background = background;
    this.buttonFace = buttonFace;
    this.buttonHighlight = buttonHighlight;
    this.buttonShadow = buttonShadow;
    this.buttonText = buttonText;
    this.icon = icon;
    this.face = face;
    this.highlight = highlight;
    this.shadow = shadow;
    this.disabled = disabled;
    this.highlightText = highlightText;
    this.scrollBar = scrollBar;
  }
  
  /**
   * This constructor takes inputs for a custom (preloaded) font and a selection of the colours as PApplet.color() values.
   * The constructor automatically assigns similar values to 'duplicate' colours, cutting down the number of individual
   * colour values that you need to assign.
   * 
   * @param root        points back to the processing PApplet used to call the MyGUI library.
   * @param font        preloaded PFont reference to define the font used for text.
   * @param fontSize    the size of font to use for elements.
   * @param buttonFace  the color for button faces.
   * @param buttonHighlight  the color for highlights on buttons.
   * @param buttonShadow  the color for shadows/alternate colours on buttons. 
   * @param buttonText  the color for text on buttons.
   * 
   */
  public MyGUIStyle(PApplet root, PFont font, int fontSize, int buttonFace, int buttonHighlight, int buttonShadow,
    int buttonText)
  {
    this._root = root;  
    this.font = _root.loadFont("ArialNarrow-48.vlw");
    this.font = font;
    this.fontSize = fontSize;
    this.background =  _root.color(204, 204, 204, transparency);
    this.buttonFace = buttonFace;
    this.buttonHighlight = buttonHighlight;
    this.buttonShadow = buttonShadow;
    this.buttonText = buttonText;
    this.icon = buttonText;
    this.face = buttonFace;
    this.highlight = buttonHighlight;
    this.shadow = buttonShadow;
    this.disabled = tintColor(buttonFace, background);
    this.highlightText = buttonHighlight;
    this.scrollBar = background;
  } 
  
  /**
   * This method sets the colours of this style to the defaults, essentially resetting
   * to a blue layout. The method is usually called in one of the two basic constructors.
   * <b>Note:</b> This method always sets the colours to shades of blue, regardless of the 
   * more specific constructors that may have been used.
   *
   */
  public void setDefaultColors() {
    // Storage method to save repetition in constructors
    this.background =  _root.color(204, 204, 204, transparency);
    this.buttonFace =  _root.color(102, 124, 196, transparency);
    this.buttonHighlight =  _root.color(137, 157, 221, transparency);
    this.buttonShadow =  _root.color(78, 93, 140, transparency);
    this.buttonText =  _root.color(0, 0 ,0, transparency);
    this.icon =  _root.color(0, 0, 0, transparency);
    this.face =  _root.color(102, 124, 196, transparency);
    this.highlight =  _root.color(137, 157, 221, transparency);
    this.shadow =  _root.color(78, 93, 140, transparency);
    this.disabled = tintColor(_root.color(200), highlight, 0.2f);
    this.highlightText =  _root.color(78, 93, 140, transparency);
    this.scrollBar =  _root.color(207, 217, 251, transparency);
  }
  
  // Setter methods - note all variables are public and can be modified using dot syntax
  public void setFont(PFont newFont) {
    font = newFont;
  }
  
  public void setFont(PFont newFont, int newFontSize) {
    font = newFont;
    fontSize = newFontSize;
  }  
  
  /**
   * Sets the stroke weights of all lines drawn, this may have the effect of 'beefing up'
   * buttons and causing vector drawn icons to be more chunky then intended. The default weight is 1.
   * 
   * @param weight  the new line weight to be set.
   */
  public void setStrokeWeight(int weight) {
    strokeWeight = weight;
  }
  
  /**
   * Sets the padding value used to add a spacer between the edge of a MyGUI component such
   * as a button and the internal contents such as text or an icon. The specific usage and
   * effect of increasing padding is not defined here and may alter or be ignored in certain
   * classes. The default padding value is 1.
   * 
   * @param pad  the new padding value to use. 
   */
  public void setPadding(int pad) {
    padding = pad;
  }
  
  // this method alters all the colours by tinting them
  /**
   * This tint method alters all the colours used in this style based off the hue/shade of
   * the specified color value (c). The tint method attemps to preserve the contrast of the
   * original colours (usually the default blue colours).
   * 
   * @param c  the color value to use for tinting.
   */
  public void tintColor(int c) {
    this.background = tintColor(background, c);
    this.buttonFace = tintColor(buttonFace, c);
    this.buttonHighlight = tintColor(buttonHighlight, c);
    this.buttonShadow = tintColor(buttonShadow, c);
    this.buttonText = tintColor(buttonText, c);
    this.icon = tintColor(icon, c);
    this.face = tintColor(face, c);
    this.highlight = tintColor(highlight, c);
    this.shadow = tintColor(shadow, c);
    this.highlightText = tintColor(highlightText, c);
    this.disabled = tintColor( _root.color(200), highlight, 0.2f);
    this.scrollBar = tintColor(scrollBar, c);
  }
  
  // alternative tint, resets to default colours first
  /**
   * This tint method resets all the colours to the default value and then alters them
   * based off the hue/shade of the specified color value (c). The tint method attempts to
   * preserve the constrast of the original colours.
   */
  public void tintDefault(int c) {
    setDefaultColors();
    tintColor(c);
  }

  // calls tintColor with maximum amount
  /**
   * This tint method tints a color value based off another color value using
   * the full saturation of the tint colour. You should compare this to the other tint
   * method below.
   * 
   * @param   c     the base colour that will be tinted.
   * @param   tint  the colour used for tinting.
   * @return  the new tinted color value
   * @see     #tintColor(int c, int tint, float str)
   */
  public int tintColor(int c, int tint) {
    return tintColor(c, tint, 1.0f);
  }
                  
  // sub-method, returns a single tinted value
  /**
   * This tint method tints a color value based off another color value using a
   * custom (strength) of the tint colour. For example, using a strength of 0.5f will apply
   * half the tint colour to the base colour. This may be useful for applying a mild tint
   * to another colour based off a stronger more saturated colour.
   * 
   * @param   c     the base colour that will be tinted.
   * @param   tint  the colour used for tinting.
   * @param   str   the strength of saturation to be used when tinting.
   * @return  the new tinted color value
   * @see     #tintColor(int c, int tint, float str)
   */
  public int tintColor(int c, int tint, float str) {
    float br = (_root.brightness(c) + _root.brightness(tint)) / 2 / 255;
    float r = (_root.red(tint)*str + _root.red(c)*(1-str)) * br;
    float g = (_root.green(tint)*str + _root.green(c)*(1-str)) * br;
    float b = (_root.blue(tint)*str + _root.blue(c)*(1-str)) * br;
    return _root.color(PApplet.round(r), PApplet.round(g), PApplet.round(b), _root.alpha(c));
  }
  
  /**
   * Set transparency sets the value of all the colours used in MyGUI style. It accepts a
   * floating value usually between 0.0f and 1.0f.
   * 
   * @param a  alpha / transparency for all colours.
   */
  public void setTransparency(float a) {
    transparency = a;
    this.background = updateColorTransparency(background, a);
    this.buttonFace = updateColorTransparency(buttonFace, a);
    this.buttonHighlight = updateColorTransparency(buttonHighlight, a);
    this.buttonShadow = updateColorTransparency(buttonShadow, a);
    this.buttonText = updateColorTransparency(buttonText, a);
    this.icon = updateColorTransparency(icon, a);
    this.face = updateColorTransparency(face, a);
    this.highlight = updateColorTransparency(highlight, a);
    this.shadow = updateColorTransparency(shadow, a);
    this.disabled = updateColorTransparency(disabled, a);
    this.highlightText = updateColorTransparency(highlightText, a);
    this.scrollBar = updateColorTransparency(scrollBar, a);    
  }
  
  /**
   * Set transparency sets the value of all the colours used in MyGUI style. It accepts an
   * integer value usually between 0 and 255.
   * 
   * @param a  alpha / transparency for all colours.
   */
  public void setTransparency(int a) {
    setTransparency((float)a);
  }
  
  private int updateColorTransparency(int c, float a) {
    return _root.color(_root.red(c), _root.green(c), _root.blue(c), a); 
  }
  
  // Note: All values are public can be easily accessed using dot sytax
  
  // Creates a copy/clone e.g. if a variant style is needed
  public MyGUIStyle copy() {
    // Create new style object using existing colours/fonts
    MyGUIStyle cst = new MyGUIStyle(_root, font, fontSize, background, buttonFace, buttonHighlight, buttonShadow, buttonText, icon, face, highlight, shadow, disabled, highlightText, scrollBar);
    cst.setStrokeWeight(strokeWeight);
    cst.setPadding(padding);
    return cst;
  }
}
